package main

import (
	"emailconfig"
	"encoding/base64"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"regexp"
	"strings"
	"time"

	"github.com/emersion/go-message"
	"github.com/knadh/go-pop3"
	"golang.org/x/text/encoding/simplifiedchinese"
	"gopkg.in/gomail.v2"
)

type Charset string

const (
	UTF8    = Charset("UTF-8")
	GB18030 = Charset("GB18030")
)

// Base64Encode encodes a string to Base64
func Base64Encode(input string) string {
	return base64.StdEncoding.EncodeToString([]byte(input))
}

// Base64Decode decodes a Base64 encoded string
func Base64Decode(input string) (string, error) {
	decoded, err := base64.StdEncoding.DecodeString(input)
	if err != nil {
		return "", err
	}
	return string(decoded), nil
}

func findstr(str string, reg string) string {
	re := regexp.MustCompile(reg)
	match := re.FindString(str) // 直接查找整个匹配字符串，而不是子匹配项的slice
	if match != "" {            // 检查是否找到了匹配项且不为空字符串
		return string(match) // 这里可能需要进一步处理以去除<和>字符，例如使用strings.Trim()函数。
	} else {
		fmt.Println("没有找到匹配的内容")
	}
	return ""
}

func ConvertByte2String(byte []byte, charset Charset) string {
	var str string
	switch charset {
	case GB18030:
		var decodeBytes, _ = simplifiedchinese.GB18030.NewDecoder().Bytes(byte)
		str = string(decodeBytes)
	case UTF8:
		fallthrough
	default:
		str = string(byte)
	}
	return str
}

func main() {

	listConfig := emailconfig.GetEmilConfig()
	mapData := emailconfig.ArraryMap(listConfig)
	configSelf := emailconfig.GetEmilConfigSelf()

	p := pop3.New(pop3.Opt{
		Host:       configSelf.StrPOP3Server,
		Port:       configSelf.IPOP3Port,
		TLSEnabled: configSelf.TLSEnabled,
	})

	c, err := p.NewConn()
	if err != nil {
		log.Fatal(err)
	}
	defer c.Quit()

	d := gomail.NewDialer(configSelf.StrStmpServer, configSelf.IStmpPort, configSelf.StrUserName, configSelf.StrPass)

	if err := c.Auth(configSelf.StrUserName, configSelf.StrPass); err != nil {
		log.Fatal(err)
	}

	workDirTemp, _ := os.Getwd()
	workDir := workDirTemp + "\\path\\"
	os.MkdirAll(workDir, 0755) // MkdirAll 创建所有不存在的文件夹

	var listFinish []int
	//for {
	count, size, _ := c.Stat()
	fmt.Println("total messages=", count, "size=", size)

	msgs, _ := c.List(0)
	fmt.Println(listFinish)
	for _, m := range msgs {

		bRet := false
		for _, f := range listFinish {
			if f == m.ID {
				bRet = true
			}
		}

		if bRet {
			continue
		}

		msg, _ := c.Retr(m.ID)

		from := findstr(msg.Header.Get("from"), "\\<([^>]*)\\>")
		from1 := strings.Replace(from, "<", "", -1)
		from2 := strings.Replace(from1, ">", "", -1)

		var strsub string
		strsubTemp := msg.Header.Get("subject")
		sub := strings.Split(strsubTemp, "?")
		if len(sub) > 3 {
			strsubTemp, err := Base64Decode(sub[3])
			strsub = strsubTemp
			if err != nil {
				log.Fatal(err)
			}
		} else {
			strsub = strsubTemp
		}

		v, ok := mapData[strsub]
		if ok {
			fmt.Println("\n\n接受到符合转发条件邮件信息：  id=", m.ID, "size=", m.Size, "subject=", strsub, "strFrom=", from2)
			listFinishTemp := append(listFinish, m.ID)
			listFinish = listFinishTemp

			strbody, isFile, files := txtBody(workDir, msg, msg.Body)
			sendMsg(v, d, strbody, isFile, files)
		}

	}
	time.Sleep(time.Millisecond * 5000)
	//}

	// absPath, err := os.Getwd()
	// if err != nil {

	// }
	// fmt.Println("absPath=", absPath)

	// result := emilconfig.Add(5, 3)
	// fmt.Println("result=", result)

	// for _, config := range listConfig {
	// 	fmt.Println("subject=", config.Subject, "strFrom=", config.StrFrom, "strTo=", config.StrTo)
	// }

	// for k, v := range mapData {
	// 	fmt.Println("result=", k, "v", v)
	// }

	// Pull all messages on the server. Message IDs go from 1 to N.
	// for id := 1; id <= count; id++ {
	// 	m, _ := c.Retr(id)

	// 	fmt.Println(id, "=", m.Header.Get("subject"))
	// 	fmt.Println("id=", m.ID, "size=", m.Size, "subject", m.Header.Get("subject"))

	// }

	// // 发送邮件
	// if err := d.DialAndSend(m); err != nil {
	// 	log.Fatal(err) // 打印错误信息并退出程序
	// } else {
	// 	log.Println("Email sent successfully!") // 邮件发送成功信息
	// }

	// for id := 1; id <= count; id++ {
	// 	c.Dele(id)
	// }
}

func txtBody(workDir string, msg *message.Entity, body io.Reader) (string, bool, []string) {

	mediaType, _, _ := msg.Header.ContentType()
	filepxi := time.Now().Format("20060102150405")

	var strbody string
	var isFiles bool
	var files []string
	if strings.HasPrefix(mediaType, "multipart/") {
		mr := msg.MultipartReader()
		for {
			part, err := mr.NextPart()
			if err == io.EOF {
				break // 没有更多部分了
			}

			body, err := ioutil.ReadAll(part.Body) // 读取部分内容
			//fmt.Println("Part Content-Type2:", part.Header.Get("Content-Type")) // 打印内容类型，例如 text/plain 或 text/html 等。
			if err != nil {
				panic(err) // 处理错误情况
			}

			if strings.HasPrefix(part.Header.Get("Content-Type"), "text/plain") {

				conType := part.Header.Get("Content-Type")
				strbody = string(body) // 打印部分内容。
				if strings.Contains(conType, "gb18030") {
					if strings.Contains(conType, "base64") {
						decodedBytes, err := base64.StdEncoding.DecodeString(strbody)
						if err != nil {
							log.Fatalf("Failed to decode: %v", err)
						}
						sssss2 := ConvertByte2String(decodedBytes, Charset("GB18030"))
						strbody = sssss2
					} else {
						sssss3 := ConvertByte2String(body, Charset("GB18030"))
						strbody = sssss3
					}
				}

			} else if strings.HasPrefix(part.Header.Get("Content-Type"), "multipart/") {

				// 解析邮件消息体
				strBody := string(body)

				sub := strings.Split(strBody, "\n")
				for i := 0; i < len(sub); i++ {

					if strings.Contains(sub[i], "text/plain") {
						i++

						if strings.Contains(sub[i], "gb18030") {
							i++
							if strings.Contains(sub[i], "base64") {
								i++
								i++
								decodedBytes, err := base64.StdEncoding.DecodeString(sub[i])
								if err != nil {
									log.Fatalf("Failed to decode: %v", err)
								}
								sssss1 := ConvertByte2String(decodedBytes, Charset("GB18030"))
								strbody = sssss1
							} else {
								i++
								i++
								sssss1 := ConvertByte2String([]byte(sub[i]), Charset("GB18030"))
								strbody = sssss1
							}
						}
					}
				}

			} else if strings.HasPrefix(part.Header.Get("Content-Type"), "application/") {
				strpart := strings.Split(part.Header.Get("Content-Type"), ";")
				for i := 0; i < len(strpart); i++ {
					if strings.Contains(strpart[i], "name") {
						filename := strpart[i]
						filename = strings.TrimPrefix(strings.Trim(filename, " "), "name=\"") // 去除前缀和引号以获取纯净文件名
						filename = strings.TrimSuffix(filename, "\"")
						// 打印附件名
						filenameTemp := workDir + "\\" + filepxi + filename

						filesTemp := append(files, filenameTemp)
						files = filesTemp
						isFiles = true
						saveFile(filenameTemp, body)
					}
				}
			} else if part.Header.Get("Content-Disposition") != "" { // 判断是否为附件部分
				_, mediaParams, _ := part.Header.ContentType()
				fmt.Println("part.Header", mediaParams)

				isFiles = true
				filename := part.Header.Get("Content-Disposition") // 获取文件名，例如：attachment; filename="example.pdf"
				fmt.Println(filename)
				filename = strings.TrimPrefix(filename, "attachment; filename=\"") // 去除前缀和引号以获取纯净文件名
				filename = strings.TrimSuffix(filename, "\"")                      // 去除后缀引号以获取纯净文件名
				// 打印附件名
				filenameTemp := workDir + "\\" + filepxi + filename

				filesTemp := append(files, filenameTemp)
				files = filesTemp
				saveFile(filenameTemp, body)
			} else {

			}
		}
	}
	fmt.Println("原邮件：     strbody=", strbody, " isFiles=", isFiles, " files=", files)
	return strbody, isFiles, files
}

func sendMsg(v emailconfig.Config, d *gomail.Dialer, context string, isfile bool, files []string) {
	m := gomail.NewMessage()
	m.SetHeader("From", v.StrFrom)      // 发送者邮件地址
	m.SetHeader("To", v.StrTo)          // 接收者邮件地址
	m.SetHeader("Subject", v.SubjectTo) // 邮件主题
	m.SetBody("text/plain", context)    // 邮件正文

	fmt.Println("开始发送邮件：    StrFrom=", v.StrFrom, "To=", v.StrTo, "Subject=", v.SubjectTo, "context", context)
	if isfile {
		for _, f := range files {

			fmt.Println("发送邮件附件：   attachment: ", f)
			m.Attach(f)
		}
	}

	// 发送邮件
	if err := d.DialAndSend(m); err != nil {
		log.Fatal(err) // 打印错误信息并退出程序
	} else {
		log.Println("Email sent successfully!") // 邮件发送成功信息
	}
}

func saveFile(fileName string, body []byte) {
	// 将附件内容写入文件（可选）
	file, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
	if err != nil {
		fmt.Println("附件打开失败")
	}

	ncontent, err := file.Write(body)
	//err = ioutil.WriteFile(file, content, 0644) // 将附件保存到磁盘上（例如：example.pdf）
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("保存附件:  ", fileName, "       文件长度：", ncontent)
	file.Close()
}
